package fox.framework.rpc.server.dispatcher.invoke;

import fox.framework.rpc.common.ReflectionUtils;
import fox.framework.rpc.exception.RpcInvocationException;
import fox.framework.rpc.server.dispatcher.router.RouteMapping;
import fox.framework.rpc.server.message.request.RpcServerRequest;
import fox.framework.rpc.server.message.response.RpcServerResponse;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author cuichao
 * @Description: ReflectionProvideInvokerChain
 * @Date: create in 2021/1/13 21:53
 */
public class ReflectionProvideInvokerChain extends ProvideInvokerChain {

    private RouteMapping mapping;

    public ReflectionProvideInvokerChain(List<ProvideInvoker> chains, RouteMapping mapping) {
        super(chains);
        this.mapping = mapping;
    }

    @Override
    protected void invoke(RpcServerRequest request, RpcServerResponse response) throws Throwable{
        Method method = mapping.getInvoker();
        Object instance = mapping.getTarget();
        try {
            Object[] requestBody = request.getRequestBody();
            ReflectionUtils.makeAccessible(method);
            Object invoke = method.invoke(instance, requestBody);
            response.setStatus(200);
            response.setEntityBody(invoke);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
        catch (IllegalArgumentException ex) {
            throw new RpcInvocationException("ProvideInvoker configuration seems to be invalid: tried calling method [" + method + "] on target [" + instance + "]", ex);
        }
        catch (IllegalAccessException ex) {
            throw new RpcInvocationException("Could not access method [" + method + "]", ex);
        }
    }

}
